package service

import (
	"context"
	"errors"
	"fmt"
	"github.com/wonderivan/logger"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"time"
)

var Daemonset daemonset

type daemonset struct{}

type daemonsetCell appsv1.DaemonSet

type DaemonsetResp struct {
	Total int                `json:"total`
	Items []appsv1.DaemonSet `json:"items"`
}

func (d daemonsetCell) GetCreation() time.Time {
	return d.CreationTimestamp.Time
}

func (d daemonsetCell) GetName() string {
	return d.Name
}

func (d *daemonset) toCells(daemonsets []appsv1.DaemonSet) []DataCell {
	cells := make([]DataCell, len(daemonsets))
	for i := range daemonsets {
		cells[i] = daemonsetCell(daemonsets[i])
	}
	return cells
}

func (d *daemonset) fromCells(cells []DataCell) []appsv1.DaemonSet {
	daemonsets := make([]appsv1.DaemonSet, len(cells))
	for i := range cells {
		daemonsets[i] = appsv1.DaemonSet(cells[i].(daemonsetCell))
	}
	return daemonsets
}

// 获取所有的daemonset
func (d *daemonset) GetDaemonsets(filterName, namespace string, limit, page int) (daemonsetResp *DaemonsetResp, err error) {
	dataList, err := K8s.ClientSet.AppsV1().DaemonSets(namespace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		logger.Error("获取所有的daemonset失败," + err.Error())
		return nil, errors.New("获取所有的daemonset失败," + err.Error())
	}
	fmt.Println(dataList)
	selectableData := &dataSelector{
		GenericDataList: d.toCells(dataList.Items),
		DataSelect: &DataSelectQuery{
			Filter: &FilterQuery{Name: filterName},
			Paginate: &PaginateQuery{
				Limit: limit,
				Page:  page,
			},
		},
	}
	filtered := selectableData.Filter()
	data := filtered.Sort().Paginate()

	total := len(data.GenericDataList)
	daemonsets := d.fromCells(data.GenericDataList)
	return &DaemonsetResp{
		Total: total,
		Items: daemonsets,
	}, nil
}

func (d *daemonset) GetDaemonsetDetail(daemonsetname, namespace string) (daemonset *appsv1.DaemonSet, err error) {
	daemonset, err = K8s.ClientSet.AppsV1().DaemonSets(namespace).Get(context.TODO(), daemonsetname, metav1.GetOptions{})
	if err != nil {
		logger.Error("get daemonset detail failed," + err.Error())
		return nil, errors.New("get daemonset detail failed," + err.Error())
	}
	return daemonset, nil
}

func (d *daemonset) DeleteDaemonset(daemonsetName, namespace string) (err error) {
	err = K8s.ClientSet.AppsV1().DaemonSets(namespace).Delete(context.TODO(), daemonsetName, metav1.DeleteOptions{})
	if err != nil {
		logger.Error("删除daemonset失败," + err.Error())
		return errors.New("删除daemonset失败," + err.Error())
	}
	return nil
}

type DaemonsetCreate struct {
	Name                        string                             `json:"name"`
	Namespace                   string                             `json:"namespace"`
	PodLabel                    map[string]string                  `json:"podlabel"`
	DaemonsetMetaLabel          map[string]string                  `json:"daemonsetmetalabel"`
	Annotation                  map[string]string                  `json:"annotation"`
	Image                       string                             `json:"image"`
	Cpu                         string                             `json:"cpu"`
	Memory                      string                             `json:"memory"`
	Maxunavailable              int32                              `json:"maxunavailable"`
	ContainerPort               int32                              `json:"container_port"`
	HealthCheck                 bool                               `json:"health_check"`
	HealthPath                  string                             `json:"health_path"`
	RestartPolicy               corev1.RestartPolicy               `json:"restartPolicy"`
	DaemonSetUpdateStrategyType appsv1.DaemonSetUpdateStrategyType `json:"daemonsetupdatestrategytype"`
}

/*

metadata:
  annotations:
    deprecated.daemonset.template.generation: "1"
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"DaemonSet","metadata":{"annotations":{},"name":"my-daemonset","namespace":"default"},"spec":{"selector":{"matchLabels":{"app":"my-daemon"}},"template":{"metadata":{"labels":{"app":"my-daemon"}},"spec":{"containers":[{"image":"hub.guazi-cloud.com/library/nginx","name":"daemonset-container","ports":[{"containerPort":80}]}]}}}}
  creationTimestamp: "2022-06-07T09:10:07Z"
  generation: 1
  name: my-daemonset
  namespace: default
  resourceVersion: "2002372"
  uid: 1f34930f-c82c-4405-8c3b-75d4236708d0
*/

func (d *daemonset) CreateDaemonset(data *DaemonsetCreate) (err error) {

	daemonset := &appsv1.DaemonSet{
		ObjectMeta: metav1.ObjectMeta{
			// 根据上面注释来看，metadata字段三个最重要，分别是name、namespace和labels，如果有必要则添加annotations
			Name:        data.Name,
			Namespace:   data.Namespace,
			Labels:      data.DaemonsetMetaLabel,
			Annotations: data.Annotation,
		},
		Spec: appsv1.DaemonSetSpec{
			Selector: &metav1.LabelSelector{
				MatchLabels: data.PodLabel,
			},
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Name:   data.Name,
					Labels: data.PodLabel,
				},
				Spec: corev1.PodSpec{
					Containers: []corev1.Container{
						{
							Name:  data.Name,
							Image: data.Image,
							Ports: []corev1.ContainerPort{
								{
									Name:          "http",
									Protocol:      corev1.ProtocolTCP,
									ContainerPort: data.ContainerPort,
								},
							},
						},
					},
					RestartPolicy: data.RestartPolicy,
				},
			},
			UpdateStrategy: appsv1.DaemonSetUpdateStrategy{
				Type: data.DaemonSetUpdateStrategyType,
				RollingUpdate: &appsv1.RollingUpdateDaemonSet{
					// maxunavailable和maxsurge两者配置一个即可。
					MaxUnavailable: &intstr.IntOrString{
						Type:   0,
						IntVal: data.Maxunavailable,
					},
				},
			},
		},
		Status: appsv1.DaemonSetStatus{},
	}
	if data.HealthCheck {
		daemonset.Spec.Template.Spec.Containers[0].ReadinessProbe = &corev1.Probe{
			ProbeHandler: corev1.ProbeHandler{
				HTTPGet: &corev1.HTTPGetAction{
					Path: data.HealthPath,
					Port: intstr.IntOrString{
						Type:   0,
						IntVal: data.ContainerPort,
					},
				},
			},
			InitialDelaySeconds: 30,
			TimeoutSeconds:      5,
			PeriodSeconds:       5,
		}
		daemonset.Spec.Template.Spec.Containers[0].LivenessProbe = &corev1.Probe{
			ProbeHandler: corev1.ProbeHandler{
				HTTPGet: &corev1.HTTPGetAction{
					Path: data.HealthPath,
					Port: intstr.IntOrString{
						Type:   0,
						IntVal: data.ContainerPort,
					},
				},
			},
			InitialDelaySeconds: 30,
			TimeoutSeconds:      5,
			PeriodSeconds:       5,
		}
	}
	//定义容器的limit和request资源
	daemonset.Spec.Template.Spec.Containers[0].Resources.Limits = map[corev1.ResourceName]resource.Quantity{
		corev1.ResourceCPU:    resource.MustParse(data.Cpu),
		corev1.ResourceMemory: resource.MustParse(data.Memory),
	}
	daemonset.Spec.Template.Spec.Containers[0].Resources.Requests = map[corev1.ResourceName]resource.Quantity{
		corev1.ResourceCPU:    resource.MustParse(data.Cpu),
		corev1.ResourceMemory: resource.MustParse(data.Memory),
	}
	_, err = K8s.ClientSet.AppsV1().DaemonSets(data.Namespace).Create(context.TODO(), daemonset, metav1.CreateOptions{})
	if err != nil {
		logger.Error("创建daemonset失败，" + err.Error())
		return errors.New("创建daemonset败，" + err.Error())
	}
	return nil
}
